package com.szh.edu.teacher.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.szh.common.result.Result;
import com.szh.edu.teacher.client.StudentFeignClient;
import com.szh.edu.teacher.mapper.TeacherMapper;
import com.szh.edu.teacher.service.TeacherService;
import com.szh.common.enums.LevelEnum;
import com.szh.common.enums.ResultCodeEnum;
import com.szh.common.enums.SexEnum;
import com.szh.common.exception.ServiceEduException;
import com.szh.model.Student;
import com.szh.model.Teacher;
import com.szh.vo.StudentQueryVo;
import com.szh.vo.TeacherInsertVo;
import com.szh.vo.TeacherQueryVo;
import com.szh.vo.TeacherUpdateVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author: SongZiHao
 * @date: 2023/5/8
 */
@Service
public class TeacherServiceImpl implements TeacherService {

    private static final Logger LOGGER = LoggerFactory.getLogger(TeacherServiceImpl.class);

    private static final Map<Integer, LevelEnum> LEVEL_ENUM_MAP = new HashMap<>();

    @Resource
    private TeacherMapper teacherMapper;

    @Resource
    private StudentFeignClient studentFeignClient;

    static {
        LEVEL_ENUM_MAP.put(1, LevelEnum.助教);
        LEVEL_ENUM_MAP.put(2, LevelEnum.讲师);
        LEVEL_ENUM_MAP.put(3, LevelEnum.副教授);
        LEVEL_ENUM_MAP.put(4, LevelEnum.教授);
    }

    /**
     * 根据id查询教师
     * @param id 教师id
     * @return Teacher
     */
    @Override
    public Teacher selectTeacherById(Long id) {
        LOGGER.info("selectTeacherById start....");
        LOGGER.info("待查询教师id ===> {}", id);
        Teacher teacher = teacherMapper.selectTeacherById(id);
        if (null == teacher) {
            LOGGER.error("根据此 id ===> {} 查询的教师信息为空....", id);
            throw new ServiceEduException(ResultCodeEnum.QUERY_ONE_NOT_FOUND.getCode(),
                    ResultCodeEnum.QUERY_ONE_NOT_FOUND.getMessage());
        }
        LOGGER.info("根据此 id ===> {} 查询的教师信息 ===> {}", id, JSON.toJSONString(teacher));
        return teacher;
    }

    /**
     * 查询所有教师
     * @return List<Teacher>
     */
    @Override
    public List<Teacher> selectAll() {
        LOGGER.info("selectAll start....");
        List<Teacher> teacherList = teacherMapper.selectAll();
        LOGGER.info("查询到的教师列表 ===> {}", JSON.toJSONString(teacherList));
        return teacherList;
    }

    /**
     * 条件查询教师，带分页
     * @param page 页码
     * @param limit 每页记录数
     * @param teacherQueryVo 查询条件
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> selectTeachersByConditionPage(Long page, Long limit, TeacherQueryVo teacherQueryVo) {
        LOGGER.info("selectTeachersByConditionPage start....");
        int pageNum = page == 0L ? 1 : page.intValue();
        int pageSize = limit == 0L ? 10 : limit.intValue();
        LOGGER.info("selectTeachersByConditionPage接口入参 ===> page页码：{}", pageNum);
        LOGGER.info("selectTeachersByConditionPage接口入参 ===> limit每页记录数：{}", pageSize);
        LOGGER.info("selectTeachersByConditionPage接口入参 ===> 查询条件：{}", teacherQueryVo);
        PageHelper.startPage(pageNum, pageSize);
        List<Teacher> teachers = teacherMapper.selectTeachersByConditionPage(teacherQueryVo);
        if (CollectionUtils.isEmpty(teachers)) {
            LOGGER.error("根据此条件查询的教师列表为空 ===> {}", JSON.toJSONString(teacherQueryVo));
            return new HashMap<>();
        }
        PageInfo<Teacher> pageInfo = new PageInfo<>(teachers);
        Map<String, Object> map = new HashMap<>();
        map.put("total", pageInfo.getTotal());
        map.put("records", pageInfo.getList());
        LOGGER.info("根据此条件查询的教师列表 ===> {}", JSON.toJSONString(map));
        return map;
    }

    /**
     * 新增教师
     * @param teacherInsertVo 教师新增vo类
     * @return 是否新增成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
    public boolean insertTeacher(TeacherInsertVo teacherInsertVo) {
        LOGGER.info("insertTeacher start....");
        LOGGER.info("新增教师的部分信息 ===> {}", JSON.toJSONString(teacherInsertVo));
        String name = teacherInsertVo.getName();
        Integer age = teacherInsertVo.getAge();
        String course = teacherInsertVo.getCourse();
        String address = teacherInsertVo.getAddress();
        if (StringUtils.isEmpty(name) || StringUtils.isEmpty(course) ||
            StringUtils.isEmpty(address) || age <= 0) {
            LOGGER.error("新增教师的信息中存在非法数据 ===> {}", JSON.toJSONString(teacherInsertVo));
            throw new ServiceEduException(ResultCodeEnum.ILLEGAL_PARAM.getCode(),
                    ResultCodeEnum.ILLEGAL_PARAM.getMessage());
        }
        List<Teacher> teachers = teacherMapper.selectAll();
        List<String> nameList = new ArrayList<>();
        for (Teacher teacher : teachers) {
            nameList.add(teacher.getName());
        }
        if (nameList.contains(name)) { //也可能存在重名重姓，此处判断纯属娱乐
            LOGGER.error("此 name ===> {} 已存在于数据库中，请修改姓名之后再次尝试插入!", name);
            throw new ServiceEduException(ResultCodeEnum.SAME_PROPERTIES_EXIST.getCode(),
                    ResultCodeEnum.SAME_PROPERTIES_EXIST.getMessage());
        }
        Teacher teacher = new Teacher();
        teacher.setName(name);
        teacher.setAge(age);
        teacher.setSex(teacherInsertVo.getSex() == 1 ? SexEnum.MAN.getSexId() : SexEnum.WOMAN.getSexId());
        teacher.setIntro(null == teacherInsertVo.getIntro() ? "" : teacherInsertVo.getIntro());
        teacher.setLevel(getLevelInfo(teacherInsertVo.getLevel()));
        teacher.setCourse(course);
        teacher.setAddress(address);
        teacher.setCreateTime(new Date());
        LOGGER.info("待新增教师的信息 ===> {}", JSON.toJSONString(teacher));
        int row = teacherMapper.insertTeacher(teacher);
        if (row == 0) {
            LOGGER.error("新增异常....");
            throw new ServiceEduException(ResultCodeEnum.INSERT_FAILED.getCode(),
                    ResultCodeEnum.INSERT_FAILED.getMessage());
        } else {
            LOGGER.info("新增成功 ===> {}", JSON.toJSONString(teacher));
            return true;
        }
    }

    /**
     * 根据id修改教师
     * @param teacherUpdateVo 教师修改vo类
     * @return 是否修改成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
    public boolean modifyTeacher(TeacherUpdateVo teacherUpdateVo) {
        LOGGER.info("modifyTeacher start....");
        LOGGER.info("待修改教师的部分信息 ===> {}", JSON.toJSONString(teacherUpdateVo));
        Long id = teacherUpdateVo.getId();
        Teacher modTeacher = teacherMapper.selectTeacherById(id);
        if (null == modTeacher) {
            LOGGER.error("待修改的教师记录不存在，id ===> {}", id);
            throw new ServiceEduException(ResultCodeEnum.QUERY_ONE_NOT_FOUND.getCode(),
                    ResultCodeEnum.QUERY_ONE_NOT_FOUND.getMessage());
        }
        Teacher teacher = new Teacher();
        BeanUtils.copyProperties(teacherUpdateVo, teacher);
        if (StringUtils.isEmpty(teacher.getName()) || StringUtils.isEmpty(teacher.getCourse()) ||
            teacher.getAge() <= 0 || StringUtils.isEmpty(teacher.getAddress())) {
            LOGGER.error("修改之后的教师部分信息不合法，请更正一下再次提交 ===> {}", JSON.toJSONString(teacher));
            throw new ServiceEduException(ResultCodeEnum.ILLEGAL_PARAM.getCode(),
                    ResultCodeEnum.ILLEGAL_PARAM.getMessage());
        }
        teacher.setUpdateTime(new Date());
        int row = teacherMapper.modifyTeacher(teacher);
        if (row == 0) {
            LOGGER.error("修改异常....");
            throw new ServiceEduException(ResultCodeEnum.UPDATE_FAILED.getCode(),
                    ResultCodeEnum.UPDATE_FAILED.getMessage());
        } else {
            LOGGER.info("修改成功!!!");
            return true;
        }
    }

    /**
     * 根据id逻辑删除教师
     * @param id 教师id
     * @return 是否删除成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
    public boolean removeTeacherById(Long id) {
        LOGGER.info("removeTeacherById start....");
        LOGGER.info("待删除教师id ===> {}", id);
        Teacher delTeacher = teacherMapper.selectTeacherById(id);
        if (null == delTeacher) {
            LOGGER.error("待删除教师记录不存在，id ===> {}", id);
            throw new ServiceEduException(ResultCodeEnum.QUERY_ONE_NOT_FOUND.getCode(),
                    ResultCodeEnum.QUERY_ONE_NOT_FOUND.getMessage());
        }
        int row = teacherMapper.removeTeacherById(id);
        if (row == 0) {
            LOGGER.error("删除异常....");
            throw new ServiceEduException(ResultCodeEnum.DELETE_FAILED.getCode(),
                    ResultCodeEnum.DELETE_FAILED.getMessage());
        } else {
            LOGGER.info("根据此 id ===> {} 删除教师成功，教师信息 ===> {}", id, JSON.toJSONString(delTeacher));
            return true;
        }
    }

    /**
     * 批量删除教师
     * @param teacherIds 待删教师id集合
     * @return 是否批量删除成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
    public boolean removeBatchByIds(List<Long> teacherIds) {
        LOGGER.info("removeBatchByIds start....");
        LOGGER.info("待删教师id集合 ===> {}", JSON.toJSONString(teacherIds));
        int row = teacherMapper.removeBatchByIds(teacherIds);
        if (row == teacherIds.size()) {
            LOGGER.info("批量删除成功!!!");
            return true;
        } else {
            LOGGER.error("批量删除异常....");
            throw new ServiceEduException(ResultCodeEnum.DELETE_FAILED.getCode(),
                    ResultCodeEnum.DELETE_FAILED.getMessage());
        }
    }

    /**
     * 远程接口调用：根据id查询学生
     * @param id 学生id
     * @return Student
     */
    @Override
    public Student openFeignFindStudentById(Long id) {
        LOGGER.info("openFeignFindStudentById start....");
        LOGGER.info("待查询学生id ===> {}", id);
        Result<Student> result = studentFeignClient.findStudentById(id);
        Student student = result.getData();
        if (null == student) {
            LOGGER.error("根据此 id ===> {} 远程查询的学生信息为空....", id);
            throw new ServiceEduException(ResultCodeEnum.QUERY_ONE_NOT_FOUND.getCode(),
                    ResultCodeEnum.QUERY_ONE_NOT_FOUND.getMessage());
        }
        LOGGER.info("根据此 id ===> {} 远程查询的学生信息 ===> {}", id, JSON.toJSONString(student));
        return student;
    }

    /**
     * 远程接口调用：查询所有学生
     * @return List<Student> 学生列表
     */
    @Override
    public List<Student> openFeignFindAllStudents() {
        LOGGER.info("openFeignFindAllStudents start....");
        Result<List<Student>> result = studentFeignClient.findAllStudents();
        List<Student> studentList = result.getData();
        LOGGER.info("远程查询到的学生列表 ===> {}", JSON.toJSONString(studentList));
        return studentList;
    }

    /**
     * 远程接口调用：条件查询学生，带分页
     * @param page 页码
     * @param limit 每页记录数
     * @param studentQueryVo 查询条件
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> openFeignFindStudentsByConditionPage(Long page, Long limit, StudentQueryVo studentQueryVo) {
        LOGGER.info("openFeignFindStudentsByConditionPage start....");
        Result<Map<String, Object>> result = studentFeignClient.findStudentsByConditionPage(page, limit, studentQueryVo);
        Map<String, Object> data = result.getData();
        List<Student> resultList = (List<Student>) data.get("rows");
        if (CollectionUtils.isEmpty(resultList)) {
            LOGGER.error("根据此条件远程查询的学生列表为空 ===> {}", JSON.toJSONString(studentQueryVo));
            return new HashMap<>();
        }
        LOGGER.info("根据此条件远程查询的学生总数 ===> {}", data.get("total"));
        LOGGER.info("根据此条件远程查询的学生列表 ===> {}", JSON.toJSONString(resultList));
        return data;
    }

    /**
     * 根据levelId从LEVEL_ENUM_MAP中获取对应的职称id
     * @param levelId levelId
     * @return 职称id
     */
    private Integer getLevelInfo(Integer levelId) {
        return LEVEL_ENUM_MAP.get(levelId).getLevelId();
    }
}
